/** Simulation class handles all the game logic, it has access to gamestate and ensures that all additions of data to gamestate make sense
 */

#ifndef SIMULATION_H
#define SIMULATION_H

#include <memory>
#include <set>
#include <string>
#include <vector>

class Army;
class City;
class Entity;
class Tile;

class Simulation{
    public:
        Simulation();
        void Initialise();

        void Update();

        void EndTurn();
        void EOTCities();
        void EOTImprovements();
        void EOTArmies();

        void ProcessOrder(int target_id, int mouse_button);

        void Build(std::string name);
        void BuildUnit(std::string name, int builder_id);
        City* CreateCity(int index, int owner);

        void CreateHoverImprovement(std::string building_name);
        void MoveHoverImprovement(int tile_id);
        bool PlaceImprovement(int imp_id);
        void DeleteImprovement(int id);

        bool CreateRoad(int begin, int end, std::string roadType="none");
        void SetTileWaterDistance();
        void SetTilesToFarmland();

        void ChangeImprovementConstructionPriority(int improvement_id);

        void SelectEntity(int id);
        // Tests
        void TestRoadCreation();

    private:
        void ClaimTilesWithinDistance(City* city, float distance);
        void AddTileToProvince(int province_id, int tile_index);
        bool IsTileInAProvince(int tile_index);
        int PickMostValuableTile(const std::set<int> & indices);

        void GiveOrder(Entity* entity);
        void MoveArmy(Army* army);
        void GarrisonArmy(Army* army, Entity* garrison);

        void TransferUnits(Entity* donor, Entity* reciever);

        bool IsValidBuildLocation(Tile* tile, int owner, bool wild);
        bool IsValidGarrisonLocation(Tile* tile, int owner);

        enum SimState{
            AWAITING_ORDERS,
            MOVING,
            GARRISONING,
            IMPROVING
        } simulation_state;

        std::vector<int> move_path;
};

extern Simulation* simulation;

#endif
